﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;

namespace WindowsEventLogManager
{
    public partial class EventManagerForm : Form
    {
        #region Constructors

        public EventManagerForm()
        {
            InitializeComponent();

            this.RootMachineNode = new TreeNode(Environment.MachineName);
            this.EventLogTreeView.Nodes.Add(this.RootMachineNode);
            this.Worker = new BackgroundWorker();
            this.Worker.WorkerReportsProgress = true;
            this.Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
            this.Worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
            this.Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
        }

        #endregion

        #region Properties

        private TreeNode RootMachineNode
        {
            get;
            set;
        }

        private TreeNodeCollection EventLogNodes
        {
            get
            {
                return this.RootMachineNode.Nodes;
            }
        }

        private BackgroundWorker Worker
        {
            get;
            set;
        }

        #endregion

        #region Methods

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.RefreshLogs();
        }

        private void RefreshLogs()
        {
            List<EventLog> logs = EventLog.GetEventLogs(Environment.MachineName).ToList();
            
            TreeNode[] nodes = new TreeNode[this.EventLogNodes.Count];

            this.EventLogNodes.CopyTo(nodes, 0);

            foreach (TreeNode node in nodes)
            {
                EventLogInfo log = node.Tag as EventLogInfo;

                EventLog winLog = logs.Where(r => string.Equals(r.LogDisplayName, log.DisplayName, StringComparison.OrdinalIgnoreCase)).SingleOrDefault();

                if (winLog == null)
                {
                    this.EventLogNodes.Remove(node);
                }
                else
                {
                    logs.Remove(winLog);
                }
            }

            foreach (EventLog log in logs)
            {
                this.AddLogNode(log);
            }

            this.EventLogTreeView.ExpandAll();

            this.ClearEventLogSelection();
        }

        private TreeNode AddLogNode(EventLog log)
        {
            EventLogInfo info = new EventLogInfo(log);
            info.EventRenamed += new EventHandler<EventLogRenamedEventArgs>(EventLogInfo_EventRenamed);

            TreeNode node = new TreeNode(log.LogDisplayName);
            node.Tag = info;
            node.ContextMenuStrip = this.TreeNodeContextMenuStrip;

            this.RootMachineNode.Nodes.Add(node);

            return node;
        }

        private TreeNode FindClickedNode(TreeNode parent, Point location)
        {
            TreeNode selectedNode = null;

            if (selectedNode == null)
            {
                if ((parent.Bounds.Top <= location.Y) && (parent.Bounds.Bottom >= location.Y) && (parent.Bounds.Left <= location.X) && (parent.Bounds.Right >= location.X))
                {
                    selectedNode = parent;
                }
                else
                {
                    foreach (TreeNode node in parent.Nodes)
                    {
                        selectedNode = this.FindClickedNode(node, location);

                        if (selectedNode != null)
                        {
                            break;
                        }
                    }
                }
            }

            return selectedNode;
        }

        private void ClearEventLogSelection()
        {
            this.EventLogPropertyGrid.SelectedObject = null;
            this.EventsListView.Items.Clear();

            this.ClearEventSelection();
        }

        private void ClearEventSelection()
        {
            this.EventPropertyGrid.SelectedObject = null;
        }

        private void DeleteEventLog()
        {
            if (this.EventLogTreeView.SelectedNode != null)
            {
                EventLogInfo log = this.EventLogTreeView.SelectedNode.Tag as EventLogInfo;

                if (log != null)
                {
                    this.EventLogTreeView.SelectedNode.Remove();
                    log.Delete();
                }
            }
        }

        private void ClearEventLog()
        {
            if (this.EventLogTreeView.SelectedNode != null)
            {
                EventLogInfo log = this.EventLogTreeView.SelectedNode.Tag as EventLogInfo;

                if (log != null)
                {
                    log.Clear();
                }
            }
        }

        private void RenameEventLog(string name)
        {
            if (this.EventLogTreeView.SelectedNode != null)
            {
                EventLogInfo log = this.EventLogTreeView.SelectedNode.Tag as EventLogInfo;

                if (log != null)
                {
                    log.Rename(name);
                }
            }
        }

        private void CreateEventLog()
        {
            Guid temp = Guid.NewGuid();

            EventSourceCreationData data = new EventSourceCreationData(temp.ToString(), temp.ToString());
            data.MachineName = Environment.MachineName;

            EventLog.CreateEventSource(data);

            EventLog log = new EventLog(temp.ToString(), Environment.MachineName);

            this.EventLogTreeView.SelectedNode = this.AddLogNode(log);
        }

        #endregion

        void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            EventLogEntry entry = e.UserState as EventLogEntry;

            if (entry != null)
            {
                ListViewItem item = new ListViewItem();
                item.Text = entry.EntryType.ToString();
                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, entry.TimeGenerated.ToShortDateString()));
                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, entry.TimeGenerated.ToShortTimeString()));
                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, entry.Source));
                item.SubItems.Add(new ListViewItem.ListViewSubItem(item, entry.UserName));

                item.Tag = entry;

                this.EventsListView.Items.Add(item);
            }
        }

        void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            EventLogInfo log = e.Argument as EventLogInfo;

            if (log != null)
            {
                int total = log.EventLog.Entries.Count;
                int counter = 0;

                foreach (EventLogEntry entry in log.EventLog.Entries)
                {
                    this.Worker.ReportProgress(((total-counter)/total), entry);
                    counter++;
                }
            }
        }

        void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.EventsListView.ResumeLayout();
        }

        #region UI Event Handlers

        private void ExitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void RefreshLogsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.RefreshLogs();
        }

        private void EventLogTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.ClearEventLogSelection();

            EventLogInfo log = e.Node.Tag as EventLogInfo;

            if (log == null)
            {
                this.EventLogPropertyGrid.SelectedObject = null;
            }
            else
            {
                this.EventLogPropertyGrid.SelectedObject = log;

                this.EventsListView.SuspendLayout();
                this.Worker.RunWorkerAsync(log);
            }
        }

        private void EventsListView_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.ClearEventSelection();

            if (this.EventsListView.SelectedItems.Count > 0)
            {
                EventLogEntry entry = this.EventsListView.SelectedItems[0].Tag as EventLogEntry;

                if (entry == null)
                {
                    this.EventPropertyGrid.SelectedObject = null;
                }
                else
                {
                    this.EventPropertyGrid.SelectedObject = entry;
                }
            }
        }

        private void CreateLogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.CreateEventLog();
        }

        private void DeleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.DeleteEventLog();
        }

        private void ModifySourcesToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void EventLogTreeView_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                TreeNode clicked = this.FindClickedNode(this.RootMachineNode, e.Location);

                if (clicked != null)
                {
                    this.EventLogTreeView.SelectedNode = clicked;
                }
            }
        }

        private void RenameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (RenameDialog dialog = new RenameDialog())
            {
                DialogResult result = dialog.ShowDialog(this);

                if (result == DialogResult.OK)
                {
                    this.RenameEventLog(dialog.EventLogName);
                }
            }
        }

        private void MoveLogFileToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void ClearToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.ClearEventLog();
        }

        #endregion

        #region Event Log Event Handlers

        private void EventLogInfo_EventRenamed(object sender, EventLogRenamedEventArgs e)
        {
            TreeNode node = null;

            foreach (TreeNode tempNode in this.RootMachineNode.Nodes)
            {
                if (string.Equals(tempNode.Text, e.OldName, StringComparison.Ordinal))
                {
                    node = tempNode;
                    break;
                }
            }

            if (node != null)
            {
                EventLog log = new EventLog(e.NewName);

                node.Text = e.NewName;
                node.Tag = log;
            }
        }

        #endregion
    }
}
